home *** CD-ROM | disk | FTP | other *** search
/ Programming Windows 95 with MFC / Programming Windows 95 with MFC (Microsoft Programming Series)(097-0001465)(1996).iso / CODE / Chap06 / DlgCalc / DlgCalc.cpp next >
Encoding:
C/C++ Source or Header  |  1996-04-05  |  10.3 KB  |  423 lines

  1. //***********************************************************************
  2. //
  3. //  DlgCalc.cpp
  4. //
  5. //***********************************************************************
  6.  
  7. #include <afxwin.h>
  8. #include <math.h>
  9. #include "Resource.h"
  10. #include "DlgCalc.h"
  11.  
  12. #define MAXCHARS 22
  13.  
  14. CMyApp myApp;
  15.  
  16. /////////////////////////////////////////////////////////////////////////
  17. // CMyApp member functions
  18.  
  19. BOOL CMyApp::InitInstance ()
  20. {
  21.     m_pMainWnd = new CCalcDialog;
  22.     m_pMainWnd->ShowWindow (m_nCmdShow);
  23.     m_pMainWnd->UpdateWindow ();
  24.     return TRUE;
  25. }
  26.  
  27. /////////////////////////////////////////////////////////////////////////
  28. // CCalcDialog message map and member functions
  29.  
  30. BEGIN_MESSAGE_MAP (CCalcDialog, CDialog)
  31.     ON_WM_PAINT ()
  32.     ON_WM_SYSCOMMAND ()
  33.     ON_CONTROL_RANGE (BN_CLICKED, IDC_0, IDC_9, OnDigit)
  34.     ON_BN_CLICKED (IDC_ADD, OnAdd)
  35.     ON_BN_CLICKED (IDC_SUBTRACT, OnSubtract)
  36.     ON_BN_CLICKED (IDC_MULTIPLY, OnMultiply)
  37.     ON_BN_CLICKED (IDC_DIVIDE, OnDivide)
  38.     ON_BN_CLICKED (IDC_ENTER, OnEnter)
  39.     ON_BN_CLICKED (IDC_CHGSIGN, OnChangeSign)
  40.     ON_BN_CLICKED (IDC_EXP, OnExponent)
  41.     ON_BN_CLICKED (IDC_STO, OnStore)
  42.     ON_BN_CLICKED (IDC_RCL, OnRecall)
  43.     ON_BN_CLICKED (IDC_FIX, OnFix)
  44.     ON_BN_CLICKED (IDC_CLX, OnClear)
  45.     ON_BN_CLICKED (IDC_DECIMAL, OnDecimal)
  46.     ON_BN_CLICKED (IDC_DEL, OnDelete)
  47. END_MESSAGE_MAP ()
  48.  
  49. CCalcDialog::CCalcDialog ()
  50. {
  51.     for (int i=0; i<4; i++)
  52.         m_dbStack[i] = 0.0;
  53.  
  54.     m_dbMemory = 0.0;
  55.     m_strFormat = "%0.2f";
  56.     m_bFixPending = FALSE;
  57.     m_bErrorFlag = FALSE;
  58.     m_bDecimalInString = FALSE;
  59.     m_bStackLiftEnabled = FALSE;
  60.     m_bNewX = TRUE;
  61.  
  62.     Create (IDD_CALCDLG);
  63.     m_hAccel = ::LoadAccelerators (AfxGetInstanceHandle (),
  64.         MAKEINTRESOURCE (IDR_CALCDLG));
  65.  
  66.     SetIcon (myApp.LoadIcon (IDI_CALCDLG), TRUE);
  67. }
  68.  
  69. void CCalcDialog::OnCancel ()
  70. {
  71.     DestroyWindow ();
  72. }
  73.  
  74. void CCalcDialog::PostNcDestroy ()
  75. {
  76.     delete this;
  77. }
  78.  
  79. BOOL CCalcDialog::PreTranslateMessage (MSG* pMsg)
  80. {
  81.     if (m_hAccel != NULL)
  82.         if (::TranslateAccelerator (m_hWnd, m_hAccel, pMsg))
  83.             return TRUE;
  84.     
  85.     return CDialog::PreTranslateMessage (pMsg);
  86. }
  87.  
  88. BOOL CCalcDialog::OnInitDialog ()
  89. {
  90.     CDialog::OnInitDialog ();
  91.  
  92.     CMenu* pMenu = GetSystemMenu (FALSE);
  93.     pMenu->DeleteMenu (SC_SIZE, MF_BYCOMMAND);
  94.     pMenu->DeleteMenu (SC_MAXIMIZE, MF_BYCOMMAND);
  95.     pMenu->AppendMenu (MF_SEPARATOR);
  96.     pMenu->AppendMenu (MF_STRING, IDM_SYSMENU_ABOUT,
  97.         "&About DlgCalc...");
  98.  
  99.     CStatic* pRect = (CStatic*) GetDlgItem (IDC_DISPLAYRECT);
  100.     pRect->GetWindowRect (&m_rect);
  101.     pRect->DestroyWindow ();
  102.     ScreenToClient (&m_rect);
  103.  
  104.     TEXTMETRIC tm;
  105.     CClientDC dc (this);
  106.     dc.GetTextMetrics (&tm);
  107.     m_cxChar = tm.tmAveCharWidth;
  108.     m_cyChar = tm.tmHeight - tm.tmDescent;
  109.  
  110.     DisplayXRegister ();
  111.     return TRUE;
  112. }
  113.  
  114. void CCalcDialog::OnSysCommand (UINT nID, LPARAM lParam)
  115. {
  116.     if ((nID & 0xFFF0) == IDM_SYSMENU_ABOUT) {
  117.         CAboutDialog dlg (this);
  118.         dlg.DoModal ();
  119.         return;
  120.     }
  121.     CDialog::OnSysCommand (nID, lParam);
  122. }
  123.  
  124. void CCalcDialog::OnPaint ()
  125. {
  126.     CPaintDC dc (this);
  127.     dc.DrawEdge (m_rect, EDGE_SUNKEN, BF_RECT);
  128.     UpdateDisplay (m_strDisplay);
  129. }
  130.  
  131. BOOL CCalcDialog::OnCommand (WPARAM wParam, LPARAM lParam)
  132. {
  133.     int nID = (int) LOWORD (wParam);
  134.  
  135.     if (m_bErrorFlag && (nID != IDC_CLX)) {
  136.         ::MessageBeep (MB_ICONASTERISK);
  137.         return TRUE;
  138.     }
  139.  
  140.     if (m_bFixPending &&
  141.         ((nID < IDC_0) || (nID > IDC_9)) &&
  142.         (nID != IDC_CLX)) {
  143.         ::MessageBeep (MB_ICONASTERISK);
  144.         return TRUE;
  145.     }
  146.     return CDialog::OnCommand (wParam, lParam);
  147. }
  148.  
  149. void CCalcDialog::OnDigit (UINT nID)
  150. {
  151.     char cDigit = (char) nID;
  152.  
  153.     if (m_bFixPending) {
  154.         m_strFormat.SetAt (3, cDigit - IDC_0 + 0x30);
  155.         DisplayXRegister ();
  156.         m_bFixPending = FALSE;
  157.         m_bStackLiftEnabled = TRUE;
  158.         m_bNewX = TRUE;
  159.         return;
  160.     }
  161.  
  162.     if (m_bNewX) {
  163.         m_bNewX = FALSE;
  164.         if (m_bStackLiftEnabled) {
  165.             m_bStackLiftEnabled = FALSE;
  166.             LiftStack ();
  167.         }
  168.         m_bDecimalInString = FALSE;
  169.         m_strDisplay.Empty ();
  170.     }
  171.  
  172.     int nLength = m_strDisplay.GetLength ();
  173.     if ((nLength == MAXCHARS) ||
  174.         ((nLength == (MAXCHARS - 10)) && !m_bDecimalInString))
  175.         ::MessageBeep (MB_ICONASTERISK);
  176.     else {
  177.         m_strDisplay += (cDigit - IDC_0 + 0x30);
  178.         UpdateDisplay (m_strDisplay);
  179.         m_dbStack[0] = strtod (m_strDisplay.GetBuffer (0), NULL);
  180.     }
  181. }
  182.  
  183. void CCalcDialog::OnAdd ()
  184. {
  185.     m_dbStack[0] += m_dbStack[1];
  186.     DisplayXRegister ();
  187.     DropStack ();
  188.     m_bStackLiftEnabled = TRUE;
  189.     m_bNewX = TRUE;
  190. }
  191.  
  192. void CCalcDialog::OnSubtract ()
  193. {
  194.     m_dbStack[0] = m_dbStack[1] - m_dbStack[0];
  195.     DisplayXRegister ();
  196.     DropStack ();
  197.     m_bStackLiftEnabled = TRUE;
  198.     m_bNewX = TRUE;
  199. }
  200.  
  201. void CCalcDialog::OnMultiply ()
  202. {
  203.     m_dbStack[0] *= m_dbStack[1];
  204.     DisplayXRegister ();
  205.     DropStack ();
  206.     m_bStackLiftEnabled = TRUE;
  207.     m_bNewX = TRUE;
  208. }
  209.  
  210. void CCalcDialog::OnDivide ()
  211. {
  212.     if (m_dbStack[0] == 0.0) {
  213.         m_bErrorFlag = TRUE;
  214.         ::MessageBeep (MB_ICONASTERISK);
  215.         UpdateDisplay (CString ("Divide by zero error"));
  216.     }
  217.     else {
  218.         m_dbStack[0] = m_dbStack[1] / m_dbStack[0];
  219.         DisplayXRegister ();
  220.         DropStack ();
  221.         m_bStackLiftEnabled = TRUE;
  222.         m_bNewX = TRUE;
  223.     }
  224. }
  225.  
  226. void CCalcDialog::OnEnter ()
  227. {
  228.     LiftStack ();
  229.     DisplayXRegister ();
  230.     m_bStackLiftEnabled = FALSE;
  231.     m_bNewX = TRUE;
  232. }
  233.  
  234. void CCalcDialog::OnChangeSign ()
  235. {
  236.     if (m_dbStack[0] != 0.0) {
  237.         m_dbStack[0] = -m_dbStack[0];
  238.         if (m_strDisplay[0] == '-') {
  239.             int nLength = m_strDisplay.GetLength ();
  240.             m_strDisplay = m_strDisplay.Right (nLength - 1);
  241.         }
  242.         else
  243.             m_strDisplay = "-" + m_strDisplay;
  244.         UpdateDisplay (m_strDisplay);
  245.     }
  246. }
  247.  
  248. void CCalcDialog::OnExponent ()
  249. {
  250.     if (((m_dbStack[1] == 0.0) && (m_dbStack[0] < 0.0)) ||
  251.         ((m_dbStack[1] == 0.0) && (m_dbStack[0] == 0.0)) ||
  252.         ((m_dbStack[1] < 0.0) &&
  253.         (floor (m_dbStack[0]) != m_dbStack[0]))) {
  254.         m_bErrorFlag = TRUE;
  255.         ::MessageBeep (MB_ICONASTERISK);
  256.         UpdateDisplay (CString ("Invalid operation error"));
  257.     }
  258.     else {
  259.        m_dbStack[0] = pow (m_dbStack[1], m_dbStack[0]);
  260.        DisplayXRegister ();
  261.        DropStack ();
  262.        m_bStackLiftEnabled = TRUE;
  263.        m_bNewX = TRUE;
  264.     }
  265. }
  266.  
  267. void CCalcDialog::OnStore ()
  268. {
  269.     DisplayXRegister ();
  270.     m_dbMemory = m_dbStack[0];
  271.     m_bStackLiftEnabled = TRUE;
  272.     m_bNewX = TRUE;
  273. }
  274.  
  275. void CCalcDialog::OnRecall ()
  276. {
  277.     LiftStack ();
  278.     m_dbStack[0] = m_dbMemory;
  279.     DisplayXRegister ();
  280.     m_bStackLiftEnabled = TRUE;
  281.     m_bNewX = TRUE;
  282. }
  283.  
  284. void CCalcDialog::OnFix ()
  285. {
  286.     m_bFixPending = TRUE;
  287. }
  288.  
  289. void CCalcDialog::OnClear ()
  290. {
  291.     if (m_bFixPending) {
  292.         m_bFixPending = FALSE;
  293.         return;
  294.     }
  295.  
  296.     m_bErrorFlag = FALSE;
  297.     m_dbStack[0] = 0.0;
  298.     DisplayXRegister ();
  299.     m_bStackLiftEnabled = FALSE;
  300.     m_bNewX = TRUE;
  301. }
  302.  
  303. void CCalcDialog::OnDecimal ()
  304. {
  305.     if (m_bNewX) {
  306.         m_bNewX = FALSE;
  307.         if (m_bStackLiftEnabled) {
  308.             m_bStackLiftEnabled = FALSE;
  309.             LiftStack ();
  310.         }
  311.         m_bDecimalInString = FALSE;
  312.         m_strDisplay.Empty ();
  313.     }
  314.  
  315.     int nLength = m_strDisplay.GetLength ();
  316.     if ((nLength == MAXCHARS) || (m_bDecimalInString))
  317.         ::MessageBeep (MB_ICONASTERISK);
  318.     else {
  319.         m_bDecimalInString = TRUE;
  320.         m_strDisplay += (char) 0x2E;
  321.         UpdateDisplay (m_strDisplay);
  322.         m_dbStack[0] = strtod (m_strDisplay.GetBuffer (0), NULL);
  323.     }
  324. }
  325.  
  326. void CCalcDialog::OnDelete ()
  327. {
  328.     int nLength = m_strDisplay.GetLength ();
  329.  
  330.     if (!m_bNewX && (nLength != 0)) {
  331.         if (m_strDisplay[nLength - 1] == '.')
  332.             m_bDecimalInString = FALSE;
  333.         m_strDisplay = m_strDisplay.Left (nLength - 1);
  334.         UpdateDisplay (m_strDisplay);
  335.         m_dbStack[0] = strtod (m_strDisplay.GetBuffer (0), NULL);
  336.     }
  337. }
  338.  
  339. void CCalcDialog::LiftStack ()
  340. {
  341.     for (int i=3; i>0; i--)
  342.         m_dbStack[i] = m_dbStack[i-1];
  343. }
  344.  
  345. void CCalcDialog::DropStack ()
  346. {
  347.     for (int i=1; i<3; i++)
  348.         m_dbStack[i] = m_dbStack[i+1];
  349. }
  350.  
  351. void CCalcDialog::DisplayXRegister ()
  352. {
  353.     double dbVal = m_dbStack[0];
  354.  
  355.     if ((dbVal >= 1000000000000.0) || (dbVal <= -1000000000000.0)) {
  356.         UpdateDisplay (CString ("Overflow error"));
  357.         m_bErrorFlag = TRUE;
  358.         MessageBeep (MB_ICONASTERISK);
  359.     }
  360.     else {
  361.         m_strDisplay.Format (m_strFormat, dbVal);
  362.         UpdateDisplay (m_strDisplay);
  363.     }
  364. }
  365.  
  366. void CCalcDialog::UpdateDisplay (CString& string)
  367. {
  368.     CClientDC dc (this);
  369.     CFont* pOldFont = dc.SelectObject (GetFont ());
  370.     CSize size = dc.GetTextExtent (string);
  371.  
  372.     CRect rect = m_rect;
  373.     rect.InflateRect (-2, -2);
  374.     int x = rect.right - size.cx - m_cxChar;
  375.     int y = rect.top + ((rect.Height () - m_cyChar) / 2);
  376.  
  377.     dc.ExtTextOut (x, y, ETO_OPAQUE, rect, string, NULL);
  378.     dc.SelectObject (pOldFont);
  379. }
  380.  
  381. /////////////////////////////////////////////////////////////////////////
  382. // CAboutDialog message map and member functions
  383.  
  384. BEGIN_MESSAGE_MAP (CAboutDialog, CDialog)
  385.     ON_WM_PAINT ()
  386. END_MESSAGE_MAP ()
  387.  
  388. BOOL CAboutDialog::OnInitDialog ()
  389. {
  390.     CDialog::OnInitDialog ();
  391.  
  392.     CStatic* pStatic = (CStatic*) GetDlgItem (IDC_ICONRECT);
  393.     pStatic->GetWindowRect (&m_rect);
  394.     pStatic->DestroyWindow ();
  395.     ScreenToClient (&m_rect);
  396.  
  397.     return TRUE;
  398. }
  399.  
  400. void CAboutDialog::OnPaint ()
  401. {
  402.     CPaintDC dc (this);
  403.     HICON hIcon = AfxGetMainWnd ()->GetIcon (TRUE);
  404.  
  405.     if (hIcon != NULL) {
  406.         CDC dcMem;
  407.         dcMem.CreateCompatibleDC (&dc);
  408.  
  409.         CBitmap bitmap;
  410.         bitmap.CreateCompatibleBitmap (&dc, 32, 32);
  411.         CBitmap* pOldBitmap = dcMem.SelectObject (&bitmap);
  412.  
  413.         CBrush brush (::GetSysColor (COLOR_3DFACE));
  414.         dcMem.FillRect (CRect (0, 0, 32, 32), &brush);
  415.         dcMem.DrawIcon (0, 0, hIcon);
  416.  
  417.         dc.StretchBlt (m_rect.left, m_rect.top, m_rect.Width(),
  418.             m_rect.Height (), &dcMem, 0, 0, 32, 32, SRCCOPY);
  419.  
  420.         dcMem.SelectObject (pOldBitmap);
  421.     }
  422. }
  423.